using System.Text.Json;
using Microsoft.Extensions.Caching.Memory;
using PHMEE.VibrationDataGenerator.Utils;

namespace PHMEE.VibrationDataGenerator.Data;

public class WeiLiVibDataFilesService
{
    private readonly string _folderPath;

    private readonly IMemoryCache _memoryCache;
    private const string CacheKey = "WeiLiVibDataFilesPathsCache";

    public WeiLiVibDataFilesService(IConfiguration configuration, IMemoryCache memoryCache)
    {
        _folderPath = configuration["WeiLiDataFoldersPath"]!;
        
        _memoryCache = memoryCache;
        
        // 加载并缓存文件夹下的所有文件的绝对路径
        LoadWeiLiFilesPaths();
    }

    /// <summary>
    /// 遍历 _folderPath，获取该文件夹下的所有文件夹名称，然后返回
    /// </summary>
    /// <returns></returns>
    public List<string> GetFolders()
    {
        return Directory.GetDirectories(_folderPath)
            .Select(Path.GetFileName)
            .Where(p => !string.IsNullOrWhiteSpace(p))
            .ToList()!;
    }

    /// <summary>
    /// 加载并缓存文件夹下的所有文件的绝对路径
    /// </summary>
    private void LoadWeiLiFilesPaths()
    {
        var folders = GetFolders();

        // key: 文件夹名称，value: 文件夹下的所有文件的绝对路径
        Dictionary<string, List<string>> filesPaths = new Dictionary<string, List<string>>();
        
        foreach (var folder in folders)
        {
            var folderPath = Path.Combine(_folderPath, folder);
            var filePaths = Directory.GetFiles(folderPath, "*.json");
            // 按 filePaths 的文件名排序（文件名为时间戳，所以相当于按时间戳排序）
            filePaths = filePaths.OrderBy(Path.GetFileName).ToArray();
            filesPaths.Add(folder, filePaths.ToList());
        }
        
        _memoryCache.Set(CacheKey, filesPaths);
    }
    
    /// <summary>
    /// 创建一个 WeiLiVibDataEnumerator 实例
    /// </summary>
    /// <param name="daqId"></param>
    /// <param name="daqChNumber"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public WeiLiVibDataEnumerator CreateWeiLiVibDataEnumerator(string daqId, DaqChNumber daqChNumber)
    {
        var filesPaths = _memoryCache.Get<Dictionary<string, List<string>>>(CacheKey);
        if (filesPaths is null)
        {
            throw new Exception("Failed to get WeiLi vibration data files paths from cache");
        }

        if (!filesPaths.TryGetValue(daqId, out List<string>? filePathList))
        {
            throw new Exception($"Failed to find vibration data files paths for daqId: {daqId}");
        }
        
        return new WeiLiVibDataEnumerator(filePathList, daqChNumber, _memoryCache);
    }
}

// 独立的数据枚举器
public class WeiLiVibDataEnumerator
{
    private readonly List<string> _dataFilePathList;
    private readonly DaqChNumber _daqChNumber;
    private readonly IMemoryCache _memoryCache;
    private int _currentIndex;
    
    public WeiLiVibDataEnumerator(List<string> dataFilePathFilePathList, DaqChNumber daqChNumber, IMemoryCache memoryCache)
    {
        _dataFilePathList = dataFilePathFilePathList;
        _daqChNumber = daqChNumber;
        _memoryCache = memoryCache;
        _currentIndex = 0;
    }

    // 获取数据，并根据需求循环
    public (long ts, float[] data, float coef, int freq) GetNextData()
    {
        var currentFilePath = _dataFilePathList[_currentIndex];
        _currentIndex = (_currentIndex + 1) % _dataFilePathList.Count;

        // 尝试从缓存中获取数据
        if (!_memoryCache.TryGetValue(currentFilePath, out WeiLiVibDataModel? weiLiVibDataModel))
        {
            // 缓存中不存在，读取 JSON 文件
            var json = File.ReadAllText(currentFilePath);
            weiLiVibDataModel = JsonSerializer.Deserialize<WeiLiVibDataModel>(json, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            });
            
            if (weiLiVibDataModel is null)
            {
                throw new Exception($"Failed to deserialize WeiLi vibration data from file: {currentFilePath}");
            }

            // 计算真实数据及 coef
            weiLiVibDataModel.AI0 = weiLiVibDataModel.AI0.Select(x => x * 9.8f).ToArray();
            weiLiVibDataModel.AI1 = weiLiVibDataModel.AI1.Select(x => x * 9.8f).ToArray();
            weiLiVibDataModel.AI2 = weiLiVibDataModel.AI2.Select(x => x * 9.8f).ToArray();
            weiLiVibDataModel.AI3 = weiLiVibDataModel.AI3.Select(x => x * 9.8f).ToArray();
            
            weiLiVibDataModel.AI0Coef = CoefUtils.CalculateMinCoef(weiLiVibDataModel.AI0);
            weiLiVibDataModel.AI1Coef = CoefUtils.CalculateMinCoef(weiLiVibDataModel.AI1);
            weiLiVibDataModel.AI2Coef = CoefUtils.CalculateMinCoef(weiLiVibDataModel.AI2);
            weiLiVibDataModel.AI3Coef = CoefUtils.CalculateMinCoef(weiLiVibDataModel.AI3);

            // 将数据存入缓存
            _memoryCache.Set(currentFilePath, weiLiVibDataModel);
        }
        
        if (weiLiVibDataModel is null)
        {
            throw new Exception($"Failed to get WeiLi vibration data from file: {currentFilePath}");
        }
        
        var (data, coef) = GetVibDataWithCoef(weiLiVibDataModel);
            
        return (weiLiVibDataModel.TimeStamp, data, coef, (int)weiLiVibDataModel.VibSampleFrequency);
    }
    
    private (float[], float) GetVibDataWithCoef(WeiLiVibDataModel vibData)
    {
        return _daqChNumber switch
        {
            DaqChNumber.AI0 => (vibData.AI0, vibData.AI0Coef),
            DaqChNumber.AI1 => (vibData.AI1, vibData.AI1Coef),
            DaqChNumber.AI2 => (vibData.AI2, vibData.AI2Coef),
            DaqChNumber.AI3 => (vibData.AI3, vibData.AI3Coef),
            _ => throw new Exception($"Unsupported DaqChNumber: {_daqChNumber}")
        };
    }
}

public class WeiLiVibDataModel
{
    public long TimeStamp { get; set; }

    public float VibSampleFrequency { get; set; }
    
    public float[] AI0 { get; set; } = null!;
    public float AI0Coef { get; set; }
    
    public float[] AI1 { get; set; } = null!;
    public float AI1Coef { get; set; }
    
    public float[] AI2 { get; set; } = null!;
    public float AI2Coef { get; set; }
    
    public float[] AI3 { get; set; } = null!;
    public float AI3Coef { get; set; }
}